package com.jse.util;

import java.math.BigDecimal;

/**
 * 提供一系列数学计算工具方法。
 */
public class Maths {

    /**
     * 将数值限制在指定的范围内。
     * 
     * @param val 要限制的值。
     * @param min 最小值。
     * @param max 最大值。
     * @return 限制后的值。
     */
    public static double clamp(double val, double min, double max) {
        return Math.min(max, Math.max(val, min));
    }

    /**
     * 对两个数值进行加法运算。
     * 
     * @param a 第一个加数。
     * @param b 第二个加数。
     * @return 加法结果。
     */
    public static BigDecimal add(Object a, Object b) {
        return new BigDecimal(a.toString()).add(new BigDecimal(b.toString()));
    }

    /**
     * 对两个数值进行减法运算。
     * 
     * @param a 被减数。
     * @param b 减数。
     * @return 减法结果。
     */
    public static BigDecimal sub(Object a, Object b) {
        return new BigDecimal(a.toString()).subtract(new BigDecimal(b.toString()));
    }

    /**
     * 对两个数值进行乘法运算。
     * 
     * @param a 第一个因数。
     * @param b 第二个因数。
     * @return 乘法结果。
     */
    public static BigDecimal mul(Object a, Object b) {
        return new BigDecimal(a.toString()).multiply(new BigDecimal(b.toString()));
    }

    /**
     * 对两个数值进行除法运算。
     * 
     * @param a 被除数。
     * @param b 除数。
     * @return 除法结果。
     */
    public static BigDecimal div(Object a, Object b) {
        return new BigDecimal(a.toString()).divide(new BigDecimal(b.toString()), BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 比较两个数值的大小。
     * 
     * @param a 第一个数值。
     * @param b 第二个数值。
     * @return 如果相等返回 0，如果 a 小于 b 返回 -1，如果 a 大于 b 返回 1。
     */
    public static int compareTo(Object a, Object b) {
        return new BigDecimal(a.toString()).compareTo(new BigDecimal(b.toString()));
    }

    /**
     * 把给定的总数平均分成 N 份，返回每份的数量。
     * 如果除不尽，每份的数量会增加 1。
     * 
     * @param total 总数。
     * @param count 份数。
     * @return 每份的数量。
     */
    public static int part(int total, int count) {
        return part(total, count, true);
    }

    /**
     * 把给定的总数平均分成 N 份，返回每份的数量。
     * 
     * @param total 总数。
     * @param count 份数。
     * @param isAdd 如果为 true 并且除不尽，则每份数量增加 1。
     * @return 每份的数量。
     */
    public static int part(int total, int count, boolean isAdd) {
        int quotient = total / count;
        if (isAdd && total % count != 0) {
            quotient++;
        }
        return quotient;
    }

    /**
     * 计算两个数值的绝对差值。
     * 
     * @param a 第一个数值。
     * @param b 第二个数值。
     * @return 绝对差值。
     */
    public static BigDecimal absDiff(Object a, Object b) {
        return new BigDecimal(a.toString()).subtract(new BigDecimal(b.toString())).abs();
    }

    /**
     * 计算两个数值的最大公约数。
     * 
     * @param a 第一个数值。
     * @param b 第二个数值。
     * @return 最大公约数。
     */
    public static long gcd(long a, long b) {
        while (b != 0) {
            long temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }

    /**
     * 计算两个数值的最小公倍数。
     * 
     * @param a 第一个数值。
     * @param b 第二个数值。
     * @return 最小公倍数。
     */
    public static long lcm(long a, long b) {
        return (a / gcd(a, b)) * b;
    }
    
    /**
     * 计算两点之间的欧几里得距离。
     * 
     * @param x1 第一个点的 x 坐标。
     * @param y1 第一个点的 y 坐标。
     * @param x2 第二个点的 x 坐标。
     * @param y2 第二个点的 y 坐标。
     * @return 两点之间的欧几里得距离。
     */
    public static double euclideanDistance(double x1, double y1, double x2, double y2) {
        double dx = x2 - x1;
        double dy = y2 - y1;
        return Math.sqrt(dx * dx + dy * dy);
    }
    
    /**
     * 计算三维空间中两点之间的欧几里得距离。
     * 
     * @param x1 第一个点的 x 坐标。
     * @param y1 第一个点的 y 坐标。
     * @param z1 第一个点的 z 坐标。
     * @param x2 第二个点的 x 坐标。
     * @param y2 第二个点的 y 坐标。
     * @param z2 第二个点的 z 坐标。
     * @return 两点之间的欧几里得距离。
     */
    public static double euclideanDistance3D(double x1, double y1, double z1, double x2, double y2, double z2) {
        double dx = x2 - x1;
        double dy = y2 - y1;
        double dz = z2 - z1;
        return Math.sqrt(dx * dx + dy * dy + dz * dz);
    }

    // 示例主方法
    public static void main(String[] args) {
        System.out.println("Clamp Result: " + clamp(5.5, 3.0, 10.0));
        System.out.println("Addition Result: " + add(10, 5));
        System.out.println("Subtraction Result: " + sub(10, 5));
        System.out.println("Multiplication Result: " + mul(10, 5));
        System.out.println("Division Result: " + div(10, 5));
        System.out.println("Comparison Result: " + compareTo(10, 5));
        System.out.println("Part Result: " + part(10, 3));
        System.out.println("Absolute Difference: " + absDiff(10, 5));
        System.out.println("GCD of 10 and 15: " + gcd(10, 15));
        System.out.println("LCM of 10 and 15: " + lcm(10, 15));
    }
}